import { isFunction } from './utils';
import ReactDom from './react-dom';

export const updateQueue = {
  isBatchingUpdate: false,
  updaters: [],
  batchUpdate: function () {
    updateQueue.updaters.forEach((update) => {
      update.updateComponent();
    });
    updateQueue.isBatchingUpdate = false;
    updateQueue.updaters.length = 0;
  },
};
class Updater {
  constructor(intance) {
    // 保存类的实例
    this.classInstance = intance;
    this.pendingStates = [];
    this.callbacks = [];
  }

  addState(partialState, cb) {
    // 收集state
    this.pendingStates.push(partialState);
    if (isFunction(cb)) {
      this.callbacks.push(cb);
    }
    this.emitUpdate();
  }

  emitUpdate(nextProps) {
    if (updateQueue.isBatchingUpdate) {
      updateQueue.updaters.push(this);
    } else {
      this.updateComponent(nextProps);
    }
  }
  updateComponent(nextProps) {
    if (nextProps || this.pendingStates.length > 0) {
      this.shouldUpdate(this.classInstance, nextProps, this.getState());
    }
  }

  shouldUpdate(classInstance, nextProps, newState) {
    let willUpdate = true;
    if (this.classInstance.shouldComponentUpdate) {
      willUpdate = this.classInstance.shouldComponentUpdate(
        nextProps,
        newState
      );
    }
    if (willUpdate && classInstance.componentWillUpdate) {
      classInstance.componentWillUpdate();
    }

    classInstance.state = newState;
    if (nextProps) {
      classInstance.props = nextProps;
    }
    if (willUpdate) {
      classInstance.forceUpdate();
    }
  }

  getState() {
    let { state } = this.classInstance;
    state = this.pendingStates.reduce((state, newState) => {
      if (isFunction(newState)) {
        newState = newState(state);
      }
      return { ...state, ...newState };
    }, state);
    this.pendingStates = [];
    return state;
  }
}

export class Component {
  static isReactComponent = {};

  constructor(props) {
    this.props = props;
    this.updater = new Updater(this);
  }

  setState(partialState, callback) {
    this.updater.addState(partialState, callback);
  }

  forceUpdate() {
    // 强制更新了
    if (this.constructor.contextType) {
      this.context = this.constructor.contextType._currentValue;
    }
    const oldVdom = this.oldRenderVdom;
    const newVdom = this.render();
    const oldDom = ReactDom.findDom(oldVdom);
    ReactDom.compareTwoVdom(oldDom.parentNode, oldVdom, newVdom);
    this.oldRenderVdom = newVdom;
    if (this.componentDidUpdate) {
      this.componentDidUpdate(this.props, this.state);
    }
  }
}
